package jkCore.utils;

import static org.cocos2dx.lib.Cocos2dxHelper.runOnGLThread;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Build;
import android.os.StrictMode;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;

import androidx.annotation.NonNull;

import com.google.gson.Gson;

import org.cocos2dx.lib.Cocos2dxJavascriptJavaBridge;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.MessageDigest;
import java.util.List;
import java.util.Locale;
import java.util.UUID;

public class Utils {
    private static final String TAG = "Utils";
    private static final String NATIVE_DATA = "Native_Data";

    /**
     * 在cocos全局上下文调用js代码
     *
     * @param formatScript
     * @param obj
     */
    public static void callCocos2dxJavascript(@NonNull String formatScript, @NonNull Object obj) {
        Log.d(TAG, "callCocos2dxJavascript obj = " + obj);

        String json;
        Gson gson = new Gson();
        json = gson.toJson(obj);
        Log.d(TAG, "callCocos2dxJavascript json = " + json);
        String script = String.format(formatScript, json);
        Log.d(TAG, "callCocos2dxJavascript script = " + script);
        runOnGLThread(new Runnable() {
            @Override
            public void run() {
                Cocos2dxJavascriptJavaBridge.evalString(script);
            }
        });
    }

    public static void callCocos2dxJavascript(@NonNull String formatScript, @NonNull int num) {
        Log.d(TAG, "callCocos2dxJavascript num = " + num);

        String json = String.valueOf(num);
        Log.d(TAG, "callCocos2dxJavascript json = " + json);
        String script = String.format(formatScript, json);
        Log.d(TAG, "callCocos2dxJavascript script = " + script);
        runOnGLThread(new Runnable() {
            @Override
            public void run() {
                Cocos2dxJavascriptJavaBridge.evalString(script);
            }
        });
    }

    public static void callCocos2dxJavascript(@NonNull String formatScript, @NonNull String str) {
        Log.d(TAG, "callCocos2dxJavascript str = " + str);

        String json = str;
        Log.d(TAG, "callCocos2dxJavascript json = " + json);
        String script = String.format(formatScript, json);
        Log.d(TAG, "callCocos2dxJavascript script = " + script);
        runOnGLThread(new Runnable() {
            @Override
            public void run() {
                Cocos2dxJavascriptJavaBridge.evalString(script);
            }
        });
    }

    public static void callCocos2dxJavascript(@NonNull String formatScript) {
        runOnGLThread(new Runnable() {
            @Override
            public void run() {
                Cocos2dxJavascriptJavaBridge.evalString(formatScript);
            }
        });
    }

    /**
     * 获得设备硬件标识(多种参数混合)
     *
     * @param context 上下文
     * @return 设备硬件标识
     */
    public static String getDeviceId(Context context) {
        StringBuilder sbDeviceId = new StringBuilder();

        //获得设备默认IMEI（>=6.0 需要ReadPhoneState权限）
        String imei = getIMEI(context);
        //获得AndroidId（无需权限）
        String androidid = getAndroidId(context);
        //获得设备序列号（无需权限）
        String serial = getSERIAL();
        //获得硬件uuid（根据硬件相关属性，生成uuid）（无需权限）
        String uuid = getDeviceUUID().replace("-", "");

        //追加imei
        if (imei != null && imei.length() > 0) {
            sbDeviceId.append(imei);
            sbDeviceId.append("|");
        }
        //追加androidid
        if (androidid != null && androidid.length() > 0) {
            sbDeviceId.append(androidid);
            sbDeviceId.append("|");
        }
        //追加serial
        if (serial != null && serial.length() > 0) {
            sbDeviceId.append(serial);
            sbDeviceId.append("|");
        }
        //追加硬件uuid
        if (uuid != null && uuid.length() > 0) {
            sbDeviceId.append(uuid);
        }

        //生成SHA1，统一DeviceId长度
        if (sbDeviceId.length() > 0) {
            try {
                byte[] hash = getHashByString(sbDeviceId.toString());
                String sha1 = bytesToHex(hash);
                if (sha1 != null && sha1.length() > 0) {
                    //返回最终的DeviceId
                    return sha1;
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }

        //如果以上硬件标识数据均无法获得，
        //则DeviceId默认使用系统随机数，这样保证DeviceId不为空
        return UUID.randomUUID().toString().replace("-", "");
    }

    //需要获得READ_PHONE_STATE权限，>=6.0，默认返回null
    private static String getIMEI(Context context) {
        try {
            TelephonyManager tm = (TelephonyManager)
                    context.getSystemService(Context.TELEPHONY_SERVICE);
            return tm.getDeviceId();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return "";
    }

    /**
     * 获得设备的AndroidId
     *
     * @param context 上下文
     * @return 设备的AndroidId
     */
    private static String getAndroidId(Context context) {
        try {
            return Settings.Secure.getString(context.getContentResolver(),
                    Settings.Secure.ANDROID_ID);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return "";
    }

    /**
     * 获得设备序列号（如：WTK7N16923005607）, 个别设备无法获取
     *
     * @return 设备序列号
     */
    private static String getSERIAL() {
        try {
            return Build.SERIAL;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return "";
    }

    /**
     * 获得设备硬件uuid
     * 使用硬件信息，计算出一个随机数
     *
     * @return 设备硬件uuid
     */
    private static String getDeviceUUID() {
        try {
            String dev = "3883756" +
                    Build.BOARD.length() % 10 +
                    Build.BRAND.length() % 10 +
                    Build.DEVICE.length() % 10 +
                    Build.HARDWARE.length() % 10 +
                    Build.ID.length() % 10 +
                    Build.MODEL.length() % 10 +
                    Build.PRODUCT.length() % 10 +
                    Build.SERIAL.length() % 10;
            return new UUID(dev.hashCode(),
                    Build.SERIAL.hashCode()).toString();
        } catch (Exception ex) {
            ex.printStackTrace();
            return "";
        }
    }

    /**
     * 取SHA1
     *
     * @param data 数据
     * @return 对应的hash值
     */
    private static byte[] getHashByString(String data) {
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
            messageDigest.reset();
            messageDigest.update(data.getBytes("UTF-8"));
            return messageDigest.digest();
        } catch (Exception e) {
            return "".getBytes();
        }
    }

    /**
     * 转16进制字符串
     *
     * @param data 数据
     * @return 16进制字符串
     */
    private static String bytesToHex(byte[] data) {
        StringBuilder sb = new StringBuilder();
        String stmp;
        for (int n = 0; n < data.length; n++) {
            stmp = (Integer.toHexString(data[n] & 0xFF));
            if (stmp.length() == 1)
                sb.append("0");
            sb.append(stmp);
        }
        return sb.toString().toUpperCase(Locale.CHINA);
    }

    /**
     * 解除文件防护
     */
    public static void checkFileUriExposure() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
            StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
            StrictMode.setVmPolicy(builder.build());
            builder.detectFileUriExposure();
        }
    }

    // 判断是否安装指定app

    /**
     * 判断是否安装指定app
     *
     * @param context
     * @param app_package 包名
     * @return
     */
    public static boolean isInstallApp(Context context, String app_package) {
        final PackageManager packageManager = context.getPackageManager();
        List<PackageInfo> pInfo = packageManager.getInstalledPackages(0);
        if (pInfo != null) {
            for (int i = 0; i < pInfo.size(); i++) {
                String pn = pInfo.get(i).packageName;
                if (app_package.equals(pn)) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * 跳转应用商店的指定应用
     *
     * @param appId 包名
     */
    public static void jumpToAppStore(Context context, String appId) {
        Log.d(TAG, "jumpToAppStore: appId = " + appId);

        Uri uri = Uri.parse("market://details?id=" + appId);
        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
    }

    public static synchronized String getAppName(Context context) {
        try {
            PackageManager packageManager = context.getPackageManager();
            PackageInfo packageInfo = packageManager.getPackageInfo(
                    context.getPackageName(), 0);
            int labelRes = packageInfo.applicationInfo.labelRes;
            return context.getResources().getString(labelRes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static synchronized Bitmap getAppIcon(Context context) {
        PackageManager packageManager = null;
        ApplicationInfo applicationInfo = null;
        try {
            packageManager = context.getApplicationContext()
                    .getPackageManager();
            applicationInfo = packageManager.getApplicationInfo(
                    context.getPackageName(), 0);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        if (applicationInfo == null) {
            return null;
        }
        Drawable d = packageManager.getApplicationIcon(applicationInfo);
        BitmapDrawable bd = (BitmapDrawable) d;
        return bd.getBitmap();
    }

    public static Bitmap getImageFromAssets(Context context, String fileName) {
        Bitmap image = null;
        AssetManager am = context.getResources().getAssets();
        try {
            InputStream is = am.open(fileName);
            image = BitmapFactory.decodeStream(is);
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return image;
    }

    public static String getStringFromAssets(Context context, String fileName) {
        try {
            InputStreamReader inputReader = new InputStreamReader(context.getResources().getAssets().open(fileName));
            BufferedReader bufReader = new BufferedReader(inputReader);
            String line;
            String Result = "";
            while ((line = bufReader.readLine()) != null) {
                Result += line;
            }
            return Result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void saveDataforKey(Context context, String key, String data) {
        SharedPreferences.Editor editor = context.getSharedPreferences(NATIVE_DATA, Context.MODE_PRIVATE).edit();
        editor.putString(key, data);
        editor.apply();
    }

    public static String loadDataforKey(Context context, String key) {
        SharedPreferences reader = context.getSharedPreferences(NATIVE_DATA, Context.MODE_PRIVATE);
        return reader.getString(key, "");
    }

    public static void deleteDataforKey(Activity activity, String key) {
        SharedPreferences.Editor editor = activity.getSharedPreferences(NATIVE_DATA, Context.MODE_PRIVATE).edit();
        editor.remove(key);
        editor.apply();
    }

    public static void saveInt(Context mContext, String key, int values) {
        SharedPreferences sp = mContext.getSharedPreferences(NATIVE_DATA, Context.MODE_PRIVATE);
        sp.edit().putInt(key, values).apply();
    }

    public static int getInt(Context mContext, String key, int values) {
        SharedPreferences sp = mContext.getSharedPreferences(NATIVE_DATA, Context.MODE_PRIVATE);
        return sp.getInt(key, values);
    }

    public static void saveLong(Context mContext, String key, long values) {
        SharedPreferences sp = mContext.getSharedPreferences(NATIVE_DATA, Context.MODE_PRIVATE);
        sp.edit().putLong(key, values).apply();
    }

    public static long getLong(Context mContext, String key, long values) {
        SharedPreferences sp = mContext.getSharedPreferences(NATIVE_DATA, Context.MODE_PRIVATE);
        return sp.getLong(key, values);
    }

    public static void saveFloat(Context mContext, String key, float values) {
        SharedPreferences sp = mContext.getSharedPreferences(NATIVE_DATA, Context.MODE_PRIVATE);
        sp.edit().putFloat(key, values).apply();
    }

    public static float getFloat(Context mContext, String key, float values) {
        SharedPreferences sp = mContext.getSharedPreferences(NATIVE_DATA, Context.MODE_PRIVATE);
        return sp.getFloat(key, values);
    }

    public static void saveBool(Context mContext, String key, boolean values) {
        SharedPreferences sp = mContext.getSharedPreferences(NATIVE_DATA, Context.MODE_PRIVATE);
        sp.edit().putBoolean(key, values).apply();
    }

    public static boolean getBool(Context mContext, String key, boolean values) {
        SharedPreferences sp = mContext.getSharedPreferences(NATIVE_DATA, Context.MODE_PRIVATE);
        return sp.getBoolean(key, values);
    }

    public static int getScreenWidth(Context context) {
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics dm = new DisplayMetrics();
        if (wm != null) {
            wm.getDefaultDisplay().getMetrics(dm);
        }
        return (int) (dm.widthPixels / dm.density);
    }

    public static int getScreenHeight(Context context) {
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics dm = new DisplayMetrics();
        if (wm != null) {
            wm.getDefaultDisplay().getMetrics(dm);
        }
        return (int) (dm.heightPixels / dm.density);
    }

    public static boolean isNetWorkAvailable(Context context) {
        boolean isAvailable = false;
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = cm.getActiveNetworkInfo();
        if (networkInfo != null && networkInfo.isAvailable()) {
            isAvailable = true;
        }
        return isAvailable;
    }

    /**
     * 将dp值转换为px值，保证尺寸大小不变
     */
    public static int dp2px(Context context, float dpValue) {
        float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    /**
     * 将px值转换为dp值，保证尺寸大小不变
     */
    public static int px2dp(Context context, float pxValue) {
        float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }

    public static void removeSelfFromParent(View child) {
        if (child != null) {
            ViewGroup parent = (ViewGroup) child.getParent();
            if (parent != null) {
                parent.removeView(child);
            }
        }
    }
}
